package org.pblue.tumblarity.tools;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Logger;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.pblue.appengine.AppengineDataException;
import org.pblue.appengine.AppengineDataManager;
import org.pblue.armyknife.Utils;
import org.pblue.tumblarity.data.bean.Follower;
import org.pblue.tumblarity.data.bean.Tumblelog;
import org.pblue.tumblarity.exception.TumblarityException;


public class TumblrParser {
  
  public static final String XPATH_FOLLOWERS = "//x:div[contains(@class,'follower')]";
  public static final String XPATH_FOLLOWER_NAME = "x:div[@class='info']/x:div[@class='name']/x:a";
  public static final String XPATH_FOLLOWER_AVATAR = "x:a/x:img/@src";

  @SuppressWarnings("unused")
  private static final Logger log = Logger.getLogger(TumblrParser.class.getName());

  @SuppressWarnings("rawtypes")
  public static FollowersPageBean getFollowers(Tumblelog pTumblelog, int pPage, AppengineDataManager pDataManager) throws JDOMException, TumblarityException, IOException, AppengineDataException {
    FollowersPageBean followersPageBean = new FollowersPageBean();
    
    String page = TumblrHttpTools.getPage(pTumblelog.getEmail(), pTumblelog.getTumblelog(), pTumblelog.getPassword(), pPage);
    
    if (page == null) {
      String message = "Followers page " + pPage + " of " + (pTumblelog.getTumblelog() == null || pTumblelog.getTumblelog().equals("") ? pTumblelog.getEmail() : pTumblelog.getTumblelog() + " cannot be fetched.");
      throw new TumblarityException(message);
    }
    
    //unescaped ampersands
    page = page.replaceAll("&(?!([a-zA-Z][a-zA-Z0-9]*|(#\\d+));)", "&amp;");
    //unterminated img tag
    page = page.replaceAll("src=\"http://assets.tumblr.com/images/bookmarklet_loader.gif\">", "src=\"http://assets.tumblr.com/images/bookmarklet_loader.gif\"/>");
    
    followersPageBean.setNextPage(page.indexOf(TumblrHttpTools.CONTENT_NEXT_PAGE) > -1);
    followersPageBean.setHtmlHash(page.hashCode());
    
    if (pTumblelog.getPageHtmlHash().size() <= pPage) {
      for (int i = 0; i <= pPage; i++) {
        pTumblelog.getPageHtmlHash().add("".hashCode());
      }
    }
    
    if (pTumblelog.getPageHtmlHash().get(pPage) != null && pTumblelog.getPageHtmlHash().get(pPage) == page.hashCode()) {
      followersPageBean.setNoChange(true);
      return followersPageBean;
    }
    
    if (Utils.matchPattern(page, TumblrHttpTools.CONTENT_0_FOLLOWERS) != null) {
      followersPageBean.setNoFollowers(true);
      return followersPageBean;
    }
    
    StringReader reader = new StringReader(page);
    SAXBuilder builder = new SAXBuilder();
    builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    Document doc = builder.build(reader);
    
    List followerNodes = Utils.evalXPathInHtml(XPATH_FOLLOWERS).selectNodes(doc);
    
    if (followerNodes != null && followerNodes.size() > 0) {
      AppengineDataManager dataManager = pDataManager;
      if (dataManager == null) {
        dataManager = AppengineDataManager.open();
        dataManager.begin();
      }
      
      followersPageBean.setFollowerIds(new HashSet<String>());
      
      try {
        for (Object nodeObject : followerNodes) {
          Element node = (Element) nodeObject;
          Element name = (Element) Utils.evalXPathInHtml(XPATH_FOLLOWER_NAME).selectSingleNode(node);
          
          String followerName = name.getTextTrim();
          String followerAddress = name.getAttributeValue("href");
          String followerAvatar = Utils.evalXPathInHtml(XPATH_FOLLOWER_AVATAR).valueOf(node);
          followerAvatar = followerAvatar.replaceAll("_30\\.", "_64.");
          
          Follower follower = Follower.get(Follower.generateId(followerName, pTumblelog.getId()), pTumblelog, dataManager);
          if (follower == null) {
            follower = new Follower(followerName, followerAddress, followerAvatar, pTumblelog, pPage);
          } else {
            follower.setUrl(followerAddress);
            follower.setThumbnail(followerAvatar);
            follower.setPage(pPage);
          }
          
          follower.save(dataManager);
          followersPageBean.getFollowerIds().add(follower.getId());
        }
        
        if (pDataManager == null) {
          dataManager.commit();
        }
      } finally {
        if (pDataManager == null) {
          dataManager.rollback();
          dataManager.close();
        }
      }
    } else if (page.indexOf(TumblrHttpTools.CONTENT_PREVIOUS_PAGE) > -1) {
      followersPageBean.setPageExists(false);
    }
    
    return followersPageBean;
  }
  
}
